#include "stdafx.h"
#include <boost/test/auto_unit_test.hpp>
#include <sstream>
#include "detail/bmock_out_ptr_arg_val.hpp"
#include "detail/bmock_test_control_tools.hpp"

namespace bmock {
	static const control_tools_ptr tl(new test_control_tools());
	static const char              name[] = "arg";
	static const int               val1   = 127;
	static const std::string            s_val1 = boost::lexical_cast<std::string>(val1);

	BOOST_AUTO_TEST_CASE(test_out_ptr_arg_val_get_value) {
		const arg_val_ptr p_val(make_out_arg_val(name,(int *)&val1));
		arg_checker       al(tl);
		const arg_val_str expected("",s_val1);

		BOOST_CHECK_EQUAL(expected,p_val->get_value(al));
	}

	BOOST_AUTO_TEST_CASE(test_out_ptr_arg_val_update) {
		int               val2 = 0;
		const arg_val_ptr p_val(make_out_arg_val(name,&val2));
		arg_checker       al(tl);
		const arg_val_str expected("",s_val1);

		al.set_location(location(__FILE__,__LINE__+1));
		BOOST_CHECK_NO_THROW(p_val->update(al,expected));
		BOOST_CHECK_EQUAL(val1,val2);
	}

	BOOST_AUTO_TEST_CASE(test_bool_out_ptr_arg_val_read) {
		const std::string s_value = "1";
		const bool   v = __get_out_value<bool>(s_value);
		BOOST_CHECK(v);
	}

	BOOST_AUTO_TEST_CASE(test_out_ptr_arg_val_print) {
		int               val2 = 683;
		const arg_val_ptr p_val(make_out_arg_val(name,&val2));
		const std::string      expected = std::string("OUT(")+out_arg_val::UNKNOWN+")";
		std::ostringstream        os;

		BOOST_CHECK_NO_THROW(p_val->print(os));
		BOOST_CHECK_EQUAL(expected,os.str());
	}

	BOOST_AUTO_TEST_CASE(test_double_out_ptr_get_value) {
		const char       *ptr1 = "ABCDEFG";
		raw_mem           rm_ptr(&ptr1,1);
		const arg_val_ptr p_val(make_out_arg_val(name,&ptr1));
		arg_checker       ac(tl);
		const arg_val_str expected("",rm_ptr.get_value());

		ac.set_location(location(__FILE__,__LINE__+1));
		BOOST_CHECK_EQUAL(expected,p_val->get_value(ac));
	}

	BOOST_AUTO_TEST_CASE(test_double_out_ptr_update) {
		const char       *ptr1 = "ABCDEFG";
		const char       *ptr2 = 0;
		raw_mem           rm_ptr(&ptr1,1);
		const arg_val_ptr p_val(make_out_arg_val(name,&ptr2));
		arg_checker       ac(tl);
		const arg_val_str expected("",rm_ptr.get_value());
		bool              result = true;

		ac.set_location(location(__FILE__,__LINE__+1));
		BOOST_CHECK_NO_THROW(result = p_val->update(ac,expected));
		BOOST_CHECK(!result);
		BOOST_CHECK_EQUAL(ptr1,ptr2);
	}

	typedef void *MEMORY_TAG;
	BOOST_AUTO_TEST_CASE(test_double_typed_out_ptr_get_value) {
		MEMORY_TAG  tag1 = (MEMORY_TAG)&val1;
		MEMORY_TAG *ptr1 = &tag1;
		raw_mem           rm_ptr(ptr1,1);
		const arg_val_ptr p_val(make_out_arg_val(name,ptr1));
		arg_checker       ac(tl);
		const arg_val_str expected("",rm_ptr.get_value());

		ac.set_location(location(__FILE__,__LINE__+1));
		BOOST_CHECK_EQUAL(expected,p_val->get_value(ac));
	}

	BOOST_AUTO_TEST_CASE(test_double_typed_out_ptr_update) {
		const MEMORY_TAG  tag1 = (MEMORY_TAG)&val1;
		const MEMORY_TAG *ptr1 = &tag1;
		MEMORY_TAG  tag2 = NULL;
		MEMORY_TAG *ptr2 = &tag2;
		raw_mem           rm_ptr(ptr1,1);
		const arg_val_ptr p_val(make_out_arg_val(name,ptr2));
		arg_checker       ac(tl);
		const arg_val_str expected("",rm_ptr.get_value());
		bool              result = true;

		ac.set_location(location(__FILE__,__LINE__+1));
		BOOST_CHECK_NO_THROW(result = p_val->update(ac,expected));
		BOOST_CHECK(!result);
		BOOST_CHECK_EQUAL(tag1,tag2);
	}

	struct test_custom_type {
		int i;
	};

}
namespace std {
	std::istream &operator >>(istream &is,bmock::test_custom_type &t) {
		is >> t.i;
		return is;
	}
}

namespace bmock {
	BOOST_AUTO_TEST_CASE(test_custom_out_ptr_get_value) {
		test_custom_type *ptr1 = NULL;
		const arg_val_ptr p_val(make_out_arg_val(name,&ptr1));
		arg_checker       ac(tl);
		const arg_val_str expected("", std::string("00000000") + WIN64_EXTRA_ZEROS);

		ac.set_location(location(__FILE__,__LINE__+1));
		BOOST_CHECK_EQUAL(expected,p_val->get_value(ac));
	}


	BOOST_AUTO_TEST_CASE(test_out_ptr_arg_for_coverage)
	{
		test_custom_type ptr1;
		ptr1.i=0;
		std::string s_input="8";
		std::istringstream  test_in(s_input.c_str());
		test_in>>ptr1;

	}

	template<typename T>
	struct stam_out_ptr_arg_val : public out_ptr_arg_val <T>{
		stam_out_ptr_arg_val(const char *const n,T *const vp)
			:out_ptr_arg_val<T>(n,vp)

		{}
		~stam_out_ptr_arg_val() {}

	};

	BOOST_AUTO_TEST_CASE(test_out_ptr_arg_operator) {
		int* x=new int [2];
		int* y=new int [2];
		const stam_out_ptr_arg_val<int> p_val(name,x);
		stam_out_ptr_arg_val<int> p_val1(name,y);

		BOOST_CHECK_NO_THROW(p_val1=p_val);
		delete []x;
		delete []y;
	}
}
